#ifndef ENGINE_H
#define ENGINE_H

#include <iostream>
#include <vector>
#include "UniversalIncludes.h"
#include "Screen.h"
#include "ContentManager.h"
#include "Camera.h"
#include "Revision.h"
#include "ScreenManager.h"

struct ScreenMode;

class Camera; // Forward declare because of Camera/Engine dependencies

class Engine
{
    // Fields
    public:
        // Event Logging
        std::vector<std::string> eventLog;
        // Viewing/Camera
        Camera* currentCamera;                  // Current camera in use
    private:
        // Screen info
        int screenWidth, screenHeight;
        int screenDepth;                        // Depth of window (bpp / bits per pixel)
        // General
        static Engine eInstance;
        bool isInit;                            // True when init() has been called successfully
        bool isRunning;                         // False unless loop() is running
        bool isActive;                          // False when window is not active
        Uint32 sdlFlags;                        // SDL display surface flags
        std::string title;                      // Application title
        std::vector<ScreenMode> screenModes;    // Available screen modes
        std::string revisionNumber;             // Revision number from source control
        // FPS
        int fps;                                // Frames per second
        Uint32 fpsUpdateRate;                   // Update rate to for fps, in msec
        // Graphing
        ScreenManager screenManager2D;
        ScreenManager screenManager3D;
        // Rendering
        GLfloat aspectRatio;

    // Methods
    public:
        static Engine& Instance();              // Access point to the Singleton engine class
        bool init();                            // Initialise or initialize? British or American?
        int run();                              // Start the engine (begins the game loop)
        void setTitle(std::string newTitle);    // Modify title of the game
        void quit();                            // Send quit signal
        // Add screens to 2d/3d screen manager roots
        void addScreen2D(Screen* screen, int priority = 0);
        void addScreen3D(Screen* screen, int priority = 0);
        int getFps();                           // Retrieve frames per second
        std::string getRevision();              // Retrieve source control revision number
        int getScreenWidth();
        int getScreenHeight();
        int getScreenDepth();
        // Event Logging
        void log(std::string msg);
    private:
        Engine();                               // Constructor is intentially private
        virtual ~Engine(){};
        Engine(const Engine &);                 // Prevent copy construction
        Engine & operator=(const Engine &);     // Prevent class assignment
        void loop();                            // Main game loop. Continually calls handleEvents, update, draw
        void draw();
        void update(Uint32* deltaTime);
        void handleEvents(SDL_Event* event);
        void kill();                            // Quit everything that was initialized
        bool loadWindow();                      // Load/Reload SDL Window
        bool initGL();                          // Initialize OpenGL
        bool resizeGL();                        // Setup OpenGL with respect to window dimensions
        void enumScreenModes();                 // Populate a list of available screen modes
};

// Used to store the width and height for a screen modes
struct ScreenMode
{
    ScreenMode(int w, int h)
    {
        width = w; height = h;
    }

    int width, height;
};

#endif
